package com.ldk.base.framework.dao.impl;

import java.io.Serializable;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;
import org.apache.commons.lang.StringUtils;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;

import com.ldk.base.framework.dao.IBaseDAO;
import com.ldk.base.framework.datasource.CustomSqlSessionManager;
import com.ldk.base.framework.util.BeanUtil;

/**
 * BaseDAO DAO 基类
 *
 * @param <T>
 * @author xiangwl
 */
public abstract class BaseDAO<T extends Serializable> implements IBaseDAO<T> {

    @Autowired
    protected SqlSessionTemplate defaultSqlSession;
    /**
     * 默认日志
     */
    protected Logger logger = getLogger();
    /**
     * sqlSession管理器
     */
    protected CustomSqlSessionManager sqlSessionManager = CustomSqlSessionManager.getInstance();
    private Class<?> clazz;

    protected BaseDAO() {
        clazz = this.getClass();
    }

    /**
     * 获取SqlSesssion,默认请设置为注解的sqlSession
     *
     * @return
     */
    protected SqlSession getSqlSession(String dbKey) {
        //如果为空则是默认的SqlSession
        if (StringUtils.isEmpty(dbKey))
            return defaultSqlSession;
        SqlSession sqlSession = sqlSessionManager.newSqlSession(dbKey);
        if (sqlSession == null) {
            sqlSession = defaultSqlSession;
        }
        return sqlSession;
    }

    /**
     * 获取Logger
     *
     * @param loggerName
     * @return
     */
    public Logger getLogger() {
        if (clazz != null)
            return LoggerFactory.getLogger(clazz);
        else {
            return LoggerFactory.getLogger("PROJECT");
        }
    }

    /**
     * 获取泛型类型的实体对象类全名获取类的包名
     *
     * @return
     */
    protected String getDefaultNamespace() {
        if (clazz == null)
            clazz = this.getClass();
        return clazz.getName();
    }

    /**
     * 获取实体Mapper的sqlName,如:com.sulian.shopping.framework.dao.ITestDAO.selectOne
     *
     * @param obj
     * @param sqlName
     * @return
     */
    protected String getSqlName(String sqlName) {
        String namespace = getDefaultNamespace();
        return namespace + "." + sqlName;
    }

    @Override
    public Object getMaxId(String dbKey) {
        SqlSession sqlSession = getSqlSession(dbKey);
        return sqlSession.selectOne(getSqlName("getMaxId"));
    }

    /**
     * 依赖与selectCount,所以使用此方法需要实现selectCount的SQL
     */
    @Override
    public Boolean exist(String dbKey, T query) {
        long count = selectCount(dbKey, query);
        return count > 0;
    }

    @Override
    public <V extends T> V selectOne(String dbKey, T query) {
        Assert.notNull(query);
        Map<String, Object> parms = getPageParms(query, null);
        SqlSession sqlSession = getSqlSession(dbKey);
        return sqlSession.selectOne(getSqlName("selectOne"), parms);
    }

    @Override
    public <V extends T> V selectOne(String dbKey, Map<String, Object> query) {
        Assert.notNull(query);
        SqlSession sqlSession = getSqlSession(dbKey);
        return sqlSession.selectOne(getSqlName("selectOne"), query);
    }

    /**
     * 单条数据查询（排序）
     *
     * @param query 查询条件
     * @param sort  排序
     * @return
     * @
     */
    public <V extends T> V selectOne(String dbKey, T query, Sort sort) {
        Map<String, Object> parms = getSortParms(query, sort);
        SqlSession sqlSession = getSqlSession(dbKey);
        return sqlSession.selectOne(getSqlName("selectOne"), parms);
    }

    @Override
    public <V extends T> V selectByKey(String dbKey, T query) {
        Assert.notNull(query);
        Map<String, Object> parms = BeanUtil.toMap(query);

        SqlSession sqlSession = getSqlSession(dbKey);
        return sqlSession.selectOne(getSqlName("selectByKey"), parms);
    }

    @Override
    public <V extends T> List<V> selectList(String dbKey, T query) {
        Map<String, Object> parms = BeanUtil.toMap(query);

        SqlSession sqlSession = getSqlSession(dbKey);
        return sqlSession.selectList(getSqlName("selectList"), parms);
    }

    @Override
    public <V extends T> List<V> selectListUpper(String dbKey, T query) {
        Map<String, Object> parms = BeanUtil.toMapLoc(query);

        SqlSession sqlSession = getSqlSession(dbKey);
        return sqlSession.selectList(getSqlName("selectList"), parms);
    }

    /**
     * 多条数据查询（排序）
     *
     * @param query 查询条件
     * @param sort  排序
     * @return
     * @
     */
    public <V extends T> List<V> selectList(String dbKey, T query, Sort sort) {
        Map<String, Object> parms = getSortParms(query, sort);

        SqlSession sqlSession = getSqlSession(dbKey);
        return sqlSession.selectList(getSqlName("selectList"), parms);
    }

    @Override
    public <V extends T> List<V> selectAll(String dbKey) {
        SqlSession sqlSession = getSqlSession(dbKey);
        return sqlSession.selectList(getSqlName("selectAll"));
    }

    @Override
    public <V extends T> List<V> selectList(String dbKey, T query, Pageable pageable) {
        SqlSession sqlSession = getSqlSession(dbKey);
        return sqlSession.selectList(getSqlName("selectList"), getPageParms(query, pageable));
    }

    @Override
    public <V extends T> Page<V> selectPageList(String dbKey, T query, Pageable pageable) {
        SqlSession sqlSession = getSqlSession(dbKey);
        List<V> contentList = sqlSession.selectList(getSqlName("selectPageList"),
                getPageParms(query, pageable));
        return new PageImpl<V>(contentList, pageable, this.selectCount(dbKey, query));
    }

    @Override
    public <K, V> Map<K, V> selectMap(String dbKey, T query, String mapKey) {
        Map<String, Object> parms = BeanUtil.toMap(query);

        SqlSession sqlSession = getSqlSession(dbKey);
        return sqlSession.selectMap(getSqlName("selectMap"), parms, mapKey);
    }

    /**
     * 多条数据查询（排序）
     *
     * @param query 查询条件
     * @param sort  排序
     * @return
     * @
     */
    public <K, V> Map<K, V> selectMap(String dbKey, T query, String mapKey, Sort sort) {
        Map<String, Object> parms = getSortParms(query, sort);

        SqlSession sqlSession = getSqlSession(dbKey);
        return sqlSession.selectMap(getSqlName("selectMap"), parms, mapKey);
    }

    @Override
    public <K, V> Map<K, V> selectMap(String dbKey, T query, Pageable pageable, String mapKey) {
        Map<String, Object> parms = BeanUtil.toMap(query, pageable);

        SqlSession sqlSession = getSqlSession(dbKey);
        return sqlSession.selectMap(getSqlName("selectMap"), parms, mapKey);
    }

    @Override
    public Long selectCount(String dbKey) {
        SqlSession sqlSession = getSqlSession(dbKey);
        return sqlSession.selectOne(getSqlName("selectCount"));
    }

    @Override
    public Long selectCount(String dbKey, T query) {
        Assert.notNull(query);
        Map<String, Object> parms = BeanUtil.toMap(query);

        SqlSession sqlSession = getSqlSession(dbKey);
        return sqlSession.selectOne(getSqlName("selectCount"), parms);
    }

    @Override
    public int insert(String dbKey, T entity) {
        Assert.notNull(entity);
        Map<String, Object> parms = BeanUtil.toMap(entity);
        SqlSession sqlSession = getSqlSession(dbKey);
        return sqlSession.insert(getSqlName("insert"), parms);
    }

    @Override
    public int insertUpper(String dbKey, T entity) {
        Assert.notNull(entity);
        Map<String, Object> parms = BeanUtil.toMapLoc(entity);
        SqlSession sqlSession = getSqlSession(dbKey);
        return sqlSession.insert(getSqlName("insert"), parms);
    }

    @Override
    public long insertAndGetAutoIncrementId(String dbKey, T entity, String keyField) {
        Assert.notNull(entity);

        SqlSession sqlSession = getSqlSession(dbKey);
        int row = sqlSession.insert(getSqlName("insertAndGetAutoIncrementId"), entity);

        if (row > 0) {
            Object idValue = BeanUtil.getFieldValueByName(keyField, entity);
            return BeanUtil.parseInt(idValue, 0);
        }
        return 0;
    }

    @Override
    public int delete(String dbKey, T query) {
        Assert.notNull(query);
        Map<String, Object> parms = BeanUtil.toMap(query);

        SqlSession sqlSession = getSqlSession(dbKey);
        return sqlSession.delete(getSqlName("delete"), parms);

    }

    @Override
    public int deleteByKey(String dbKey, T query) {
        Assert.notNull(query);
        Map<String, Object> parms = BeanUtil.toMap(query);

        SqlSession sqlSession = getSqlSession(dbKey);
        return sqlSession.delete(getSqlName("deleteByKey"), parms);
    }

    @Override
    public int deleteAll(String dbKey) {
        SqlSession sqlSession = getSqlSession(dbKey);
        return sqlSession.delete(getSqlName("deleteAll"));
    }

    @Override
    public int updateByKey(String dbKey, T entity) {
        Assert.notNull(entity);
        Map<String, Object> parms = BeanUtil.toMap(entity);
        SqlSession sqlSession = getSqlSession(dbKey);
        return sqlSession.update(getSqlName("updateByKey"), parms);
    }

    @Override
    public int updateUpperByKey(String dbKey, T entity) {
        Assert.notNull(entity);
        Map<String, Object> parms = BeanUtil.toMapLoc(entity);
        if (parms.containsKey("Id")) {
            parms.put("id", parms.get("Id"));
        }
        SqlSession sqlSession = getSqlSession(dbKey);
        return sqlSession.update(getSqlName("updateByKey"), parms);
    }

    @Override
    public int update(String dbKey, T entity) {
        Assert.notNull(entity);
        Map<String, Object> parms = BeanUtil.toMap(entity);
        SqlSession sqlSession = getSqlSession(dbKey);
        return sqlSession.update(getSqlName("update"), parms);
    }


    public List<LinkedHashMap> executeSql(String dbKey, String sql) {
        Assert.notNull(sql, "sql不能为null");
        if (sql == null || sql.length() < 1)
            return null;
        Map<String, Object> parms = new HashMap<>();
        parms.put("sql", sql);

        SqlSession sqlSession = getSqlSession(dbKey);

        return sqlSession.selectList(getSqlName("executeSql"), parms);
    }

    /**
     * 获取分页信息
     *
     * @param pageable
     * @return
     */
    protected RowBounds getRowBounds(Pageable pageable) {
        RowBounds rowBounds = RowBounds.DEFAULT;
        if (null != pageable)
            rowBounds = new RowBounds(pageable.getOffset(), pageable.getPageSize());
        return rowBounds;
    }

    /**
     * 获取分页查询参数
     *
     * @param obj
     * @param pageable
     * @return
     */
    protected Map<String, Object> getPageParms(T obj, Pageable pageable) {
        Map<String, Object> parms = BeanUtil.toMap(obj, getRowBounds(pageable));
        if (null != pageable && pageable.getSort() != null) {
            String sorting = pageable.getSort().toString();
            parms.put("sorting", sorting.replace(":", ""));
        }
        return parms;
    }

    /**
     * 获取分页查询参数
     *
     * @param obj
     * @param pageable
     * @return
     */
    protected Map<String, Object> getPageParms(Pageable pageable) {
        Map<String, Object> parms = BeanUtil.toMap(getRowBounds(pageable));
        if (null != pageable && pageable.getSort() != null) {
            String sorting = pageable.getSort().toString();
            parms.put("sorting", sorting.replace(":", ""));
        }
        return parms;
    }

    /**
     * 获取排序查询参数
     *
     * @param obj
     * @param sort
     * @return
     */
    protected Map<String, Object> getSortParms(T obj, Sort sort) {
        Map<String, Object> parms = BeanUtil.toMap(obj);
        if (sort != null) {
            String sorting = sort.toString();
            parms.put("sorting", sorting.replace(":", ""));
        }
        return parms;
    }

    /**
     * 获取排序查询参数
     *
     * @param obj
     * @param sort
     * @return
     */
    protected Map<String, Object> getSortParms(Sort sort) {
        Map<String, Object> parms = new HashMap<String, Object>();
        if (sort != null) {
            String sorting = sort.toString();
            parms.put("sorting", sorting.replace(":", ""));
        }
        return parms;
    }
}
